import multiprocessing
import datetime
import os
import logging
#from executer.scxmlexecuter import  ScxmlExcuter
from executer.script import ScriptExecuter
import executer.common
import psutil

SupportType = {'script':ScriptExecuter}

class Invoker():
    def __init__(self, uploadcfg, templateid, taskid, subid, runtype, info, args):
        
        
        if uploadcfg == None:
            raise ValueError('uploadconfig must not be None')
        
        if templateid == None:
            raise ValueError('templateid must not be None')
        
        if taskid == None:
            raise ValueError('taskid must not be None')
        
        if info == None:
            raise ValueError('info must not be None')
        
        if runtype not in SupportType:
            raise ValueError('not support type')
        
        self.uploadcfg = uploadcfg
        self.runtype = runtype
        self.templateid = templateid
        self.taskid = taskid
        self.subid = subid
        self.process = None
        self.queue = None
        self.status = executer.common.IDLE
        self.starttime = None
        self.endtime = None 
        self.result = None
        self.resultmessage = None
        self.addtional_mail_receiver = None
        self.info  = info
        self.args = args
        
    def Status(self):
        return self.status
    
    
    def Start(self):
        try:
            runpath = os.path.join(executer.common.RUNPATH, "%d_%d" % (self.templateid, self.taskid))
            if not os.path.exists(runpath):
                os.mkdir(runpath)
            
            self.queue = multiprocessing.Queue()
            print(self.uploadcfg.ip)
            self.process = multiprocessing.Process(target = SupportType[self.runtype], 
                                                   args = (self.queue, 
                                                           self.uploadcfg,
                                                           self.templateid, 
                                                           self.taskid, 
                                                           self.subid,
                                                           runpath,
                                                           self.info,
                                                           self.args)
                                                   )
        
            self.process.start()
            self.status = executer.common.RUN
            self.starttime = datetime.datetime.now()
        except Exception as e:
            logging.exception(e)
            self.result = executer.common.EXCEPTION
            self.resultmessage = str(e)
            self.status = executer.common.FINISH
        
    def Stop(self):
        assert(self.status == executer.common.RUN)
        if self.process:
            if self.process.is_alive():
                psp = psutil.Process(self.process.pid)
                for v in psp.get_children():
                    v.kill()
                self.process.terminate()
            
            self.process.join()
        self.status = executer.common.TERMINATE
        self.endtime = datetime.datetime.now()
    
    def Finished(self):
        if self.status == executer.common.FINISH or self.status == executer.common.TERMINATE:
            return True
        
        if self.process.is_alive():
            return False 
        
        if self.queue.qsize() != 1:
            logging.warn('queue size is not equal 1')
            self.result = executer.common.EXCEPTION
            self.resultmessage = 'queue size is not equal 1'
        else:
            result = self.queue.get()
            self.result = result['result']
            self.resultmessage = result['message']
            self.addtional_mail_receiver = result['addtional_mail_receiver']
        
        self.status = executer.common.FINISH
        self.process.join()
        
        self.endtime = datetime.datetime.now()
        return True
    